﻿using anydata.Entitys;
using Microsoft.VisualBasic;
using MongoDB.Driver;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace anydata.Services;

public class ReceptionExecutorHook : ITransient, IPostInsert, IPostReplace, IPostSetFields
{
    private const string InstanceColl = "work-instance";
    private const string ReceptionColl = "work-reception";
    private const string PublicReceptionColl = "-" + ReceptionColl;
    private readonly DataProvider provider;

    public ReceptionExecutorHook(DataProvider _provider)
    {
        provider = _provider;
    }

    async Task IPostInsert.Invoke(TokenModel token, string collectName, List<EntityBase> list)
    {
        if (collectName != InstanceColl) return;
        foreach (var item in list)
        {
            await Execute(token, item, item.status);
        }
    }

    async Task IPostReplace.Invoke(TokenModel token, string collectName, List<EntityBase> list)
    {
        if (collectName != InstanceColl) return;
        foreach (var item in list)
        {
            await Execute(token, item, item.status);
        }
    }

    async Task IPostSetFields.Invoke(TokenModel token, string collectName, CollectSetFields data)
    {
        if (collectName != InstanceColl) return;

        var instanceStatus = data.Update.SelectToken("_set_.status");
        if (instanceStatus is not null && instanceStatus.Type == JTokenType.Integer)
        {
            await ExecuteByInstanceId(token, data.Id, instanceStatus.Value<int>());
        }
    }

    public async Task ExecuteByInstanceId(TokenModel token, string id, int status)
    {
        try
        {
            var result = provider.TryGetCollection<EntityBase>(token, DataProvider.InstanceCollName);
            if (!result.success)
            {
                Console.WriteLine("获取流程实例集合失败！");
                return;
            }
            var instanceObj = await result.data.Find(i => i.id == id).FirstOrDefaultAsync();
            await Execute(token, instanceObj, status);
        }
        catch (Exception error)
        {
            Console.WriteLine("执行失败：", error.Message);
        }
    }

    public async Task Execute(TokenModel token, EntityBase instanceObj, int status)
    {
        var instance = new XWorkInstance(instanceObj);
        if (instance?.InstanceData is not null)
        {
            var formMap = instance.InstanceData.FormCollectionNameMap;
            var reception = instance.InstanceData.reception;
            if (reception is null)
            {
                return;
            }

            // 判断当前空间是不是发起单位
            var isMySpace = !string.IsNullOrEmpty(instance.applyId) && instance.belongId == instance.applyId;

            if (status < 100)
            {
                Console.WriteLine("任务提交");
                await Submit(token, reception, instance, isMySpace);
            }
            else if (status >= 200)
            {
                Console.WriteLine("任务驳回");
                await Reject(token, reception, isMySpace);
            }
            else if (status >= 100)
            {
                Console.WriteLine("任务通过");
                var result = provider.TryGetCollection<XTempData>(token, DataProvider.TempDataCollName);
                var things = await instance.InstanceData.GetThings(result.data);
                var thingId = things.ToDictionary(t => t.Key, t => t.Value.Select(x => x.id).ToList());
                await Approve(token, reception, thingId, isMySpace);
            }
        }
    }

    
    async Task Submit(TokenModel token, EntityBase reception, XWorkInstance instance, bool isMySpace = false)
    {
        var coll = provider.TryGetCollection<EntityBase>(token, PublicReceptionColl);
        if (!coll.success) return; 

        try
        {
            reception["instanceId"] = instance.id;
            reception["isReject"] = false;
            Console.WriteLine(JsonConvert.SerializeObject(reception));

            // HACK: reception.extensions["content"] 接收到是JObject，写入后变成了嵌套高维数组
            if (reception["content"] is JObject or JToken)
            {
                reception["content"] = (reception["content"] as JToken)?.ToBDocument();
            }

            var newReception = await coll.data.FindOneAndReplaceAsync(x => x.id == reception.id, reception, new()
            {
                ReturnDocument = ReturnDocument.After,
            });

            if (isMySpace)
            {
                var myColl = provider.TryGetCollection<EntityBase>(token, ReceptionColl);
                if (!myColl.success) return;

                await myColl.data.ReplaceOneAsync(x => x.id == reception.id, newReception);
            }
            Console.WriteLine(JsonConvert.SerializeObject(newReception));
            Console.WriteLine($"提交 更新任务接收完成，{(isMySpace ? "是" : "不是")}发起空间");
        }
        catch (Exception error)
        {
            Console.WriteLine("更新任务接收失败：" + error.ToString());
        }
    }

    async Task Reject(TokenModel token, EntityBase reception, bool isMySpace = false)
    {
        var coll = provider.TryGetCollection<EntityBase>(token, PublicReceptionColl);
        if (!coll.success) return;

        try
        {
            var update = Builders<EntityBase>.Update
                .Set("isReject", true);
            var newReception = await coll.data.FindOneAndUpdateAsync(x => x.id == reception.id, update, new()
            {
                ReturnDocument = ReturnDocument.After
            });

            if (isMySpace)
            {
                var myColl = provider.TryGetCollection<EntityBase>(token, ReceptionColl);
                if (!myColl.success) return;

                await myColl.data.ReplaceOneAsync(x => x.id == reception.id, newReception);
            }
            Console.WriteLine($"驳回 更新任务接收完成，{(isMySpace ? "是" : "不是")}发起空间");
        }
        catch (Exception error)
        {
            Console.WriteLine("更新任务接收失败：" + error.ToString());
        }
    }

    async Task Approve(TokenModel token, EntityBase reception, Dictionary<string, List<string>> thingId, bool isMySpace = false)
    {
        var coll = provider.TryGetCollection<EntityBase>(token, PublicReceptionColl);
        if (!coll.success) return; 

        try
        {
            // 如果采用模板办事，按照设计每一个走过的节点都会更新自己空间的公共集合，不会发生反复更新
            var update = Builders<EntityBase>.Update
                .Set("thingId", thingId)
                .Set("isReject", false)
                .Unset("previousInstanceId");
            var newReception = await coll.data.FindOneAndUpdateAsync(x => x.id == reception.id, update, new()
            {
                ReturnDocument = ReturnDocument.After
            });

            if (isMySpace)
            {
                var myColl = provider.TryGetCollection<EntityBase>(token, ReceptionColl);
                if (!myColl.success) return;

                await myColl.data.ReplaceOneAsync(x => x.id == reception.id, newReception);
            }
            Console.WriteLine(JsonConvert.SerializeObject(newReception));
            Console.WriteLine($"通过 更新任务接收完成，{(isMySpace ? "是" : "不是")}发起空间");
        }
        catch (Exception error)
        {
            Console.WriteLine("更新任务接收失败：" + error.ToString());
        }
    }
}
